<!--
 * @Description: 表单
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-11-04 16:39:23
 * @LastEditTime: 2025-06-02 10:54:30
-->
<template>
    <el-form ref="elForm" :model="modelValue" class="edit-form" :inline="inline" :label-width="labelWidth">
        <template v-for="item in options" :key="item.key">
            <el-form-item v-if="!item.hide" :label="item.label" :prop="item.key" :rules="item.rules"
                :label-width="item.labelWidth || labelWidth"
                :style="`--input-width:${getStringWidth(item.inputWidth) || myInputWidth}`">
                <slot v-if="item.slot" :name="item.slot" />
                <template v-else>
                    <!-- 日期，这里单独拎出来是因为使用动态组件的话会导致日期弹框BUG -->
                    <el-date-picker v-if="item.component == 'date-picker'" v-model="modelValue[item.key]"
                        v-bind="item.props" clearable>
                    </el-date-picker>
                    <!-- radio单选 -->
                    <el-radio-group v-else-if="item.component == 'radio'" v-model="modelValue[item.key]">
                        <template v-if="item.options">
                            <el-radio v-for="option in item.options" :key="option.value" :value="option.value"
                                v-bind="item.props">{{ option.label }}</el-radio>
                        </template>
                    </el-radio-group>
                    <!-- 其他 -->
                    <component v-else :is="`el-${item.component}`" v-model="modelValue[item.key]" v-bind="item.props"
                        clearable>
                        <!-- 下拉框 -->
                        <template v-if="item.options">
                            <el-option v-for="option in item.options" :key="option.value" :label="option.label"
                                :value="option.value"></el-option>
                        </template>
                    </component>
                </template>
                <span v-if="item.suffix" class="suffix">{{ item.suffix }}</span>
            </el-form-item>
        </template>
        <el-form-item v-if="showSearchBtn">
            <el-button type="primary" @click="$emit('submit')">搜索</el-button>
            <el-button @click="$emit('reset')">重置</el-button>
        </el-form-item>
    </el-form>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref, watch } from 'vue'
import { IFormOption } from '../types'

export default defineComponent({
    name: 'Form',
    props: {
        // 是否行内
        inline: {
            type: Boolean,
            require: false,
            default: true,
        },
        // 是否显示搜索按钮
        showSearchBtn: {
            type: Boolean,
            require: false,
            default: true,
        },
        // 表单项配置选项
        options: {
            type: Array as PropType<IFormOption[]>,
            require: true,
            default: () => [],
        },
        // v-model传参写法
        modelValue: {
            type: Object as PropType<Record<string, any>>,
            require: true,
            default: () => ({}),
        },
        labelWidth: {
            type: [String, Number],
            require: false,
            default: 80
        },
        inputWidth: {
            type: [String, Number],
            require: false,
            default: 220
        },
    },
    // `update:modelValue`为`v-model`传参固定事件写法
    emits: ['update:modelValue', 'submit', 'reset'],
    setup(props, { emit }) {
        // 表单对象
        const elForm = ref()

        // 操作父级数据
        watch(props.modelValue, (value: any) => emit('update:modelValue', value), { deep: true })

        const getStringWidth = (width?: number | string) => {
            if (typeof width === 'number') {
                return width + 'px'
            }
            return width
        }

        const myInputWidth = computed(() => getStringWidth(props.inputWidth))

        return { elForm, getStringWidth, myInputWidth }
    },
})
</script>

<style scoped lang="scss">
.edit-form:deep(.el-form-item) {
    .el-form-item__label {
        justify-content: flex-end;
        flex-direction: row-reverse;
    }

    .el-form-item__content {
        width: var(--input-width) !important;

        .suffix {
            margin-left: 8px;
        }

        .el-input,
        .el-input__inner,
        .el-input-number,
        .el-switch {
            max-width: 100%;

            &.el-date-editor--datetimerange {
                width: 350px !important;
            }
        }
    }
}
</style>